from django.shortcuts import render

from django.http import HttpResponse
from django.utils import timezone
import json
import md5

from models import User, Category, Message

# Create your views here.

# Should be placed into backend.utils
# ----------------------------------
import math
from datetime import datetime
EARTH_RADIUS = 6372797.0
def is_nearby(latitude1, longitude1, latitude2, longitude2, distance):
    """
    Decide if too GPS coordinates are close enough, regarding 'distance'(in Meter)
    """
    latitude1  = math.radians(latitude1)
    longitude1 = math.radians(longitude1)
    latitude2  = math.radians(latitude1)
    longitude2 = math.radians(longitude2)
    a = latitude1 - latitude2
    b = longitude1 - longitude2
    return distance >= (
        2 * math.asin(math.sqrt(math.pow(math.sin(a/2), 2) +
        math.cos(latitude1) * math.cos(latitude2)*math.pow(math.sin(b/2), 2)))
    )

class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, obj)
#------------------------------------

def register(request):
    # Obtain user information

    # POST contents may not be UTF8 encoded, that is,
    # SQLite3 incompitable, encoding UTF8 here to prevent this.
    register_info = json.loads(request.POST['json'].encode('utf8'))
    username = register_info['username']
    nickname = register_info['nickname']
    passkey  = md5.new(register_info['password']).hexdigest()

    # Register procedure
    response = {
        'status':'',
        'description':''
    }
    if User.objects.filter(username__exact=username).exists():
        # Registering failed if the username already exists
        response['status'] = "fail"
        response['description'] = "username exists"
    else:
        # Set up an new account
        try:
            user = User(
                username=username,
                nickname=nickname,
                passkey=passkey
            )
            user.save()
        except ():
            response['status'] = "fail"
            response['description'] = "database error"
        else:
            response['status'] = "success"

    return HttpResponse(json.dumps(response))

def resetpassword(request):
    user_info = json.loads(request.POST['json'].encode('utf8'))
    username = user_info['username']
    passkey  = md5.new(user_info['password']).hexdigest()
    new_passkey = md5.new(user_info['new password']).hexdigest()

    response = {
        'status':'',
        'description':''
    }
    if User.objects.filter(username__exact=username, passkey__exact=passkey).exists() == False:
        # Check if the provided is valid
        response['status'] = "fail"
        response['description'] = "invalid username or password"
    else:
        try:
            # Change the passkey
            user = User.objects.get(username=username)
            user.passkey = new_passkey
            user.save()
        except ():
            response['status'] = "fail"
            response['description'] = "database error"
        else:
            response['status'] = "success"

    return HttpResponse(json.dumps(response))

def login(request):
    # Obtain user information
    login_info = json.loads(request.POST['json'].encode('utf8'))
    username = login_info['username']
    passkey  = md5.new(login_info['password']).hexdigest()

    # Login procedure
    response = {
        'status':'',
        'description':''
    }
    if User.objects.filter(username__exact=username,passkey__exact=passkey).exists():
        response['status'] = "success"
    else:
        response['status'] = "fail"
        response['description'] = "invalid username or password"

    return HttpResponse(json.dumps(response))


def fetch(request):
    fetch_info = json.loads(request.POST['json'].encode('utf8'))
    username = fetch_info['username']
    passkey  = md5.new(fetch_info['password']).hexdigest()

    response = {
        'status':'',
        'description':'',
        'messages':[],
    }
    if User.objects.filter(username__exact=username,passkey__exact=passkey).exists():
        # Obtain messages from self
        user_id = User.objects.get(username=username).id
        # Add messages in  queryset to http response['messages']
        response['messages'] += Message.objects.filter(user=user_id).values()

        # Obtain messages from nearby
        # Avoid redundance: both 'from self' and 'nearby'
        messages = Message.objects.exclude(user=user_id)
        # Go through all messages from others, select the nearby,
        # turn satisfying message into single-value queryset,
        # generate dictionary by calling QuerySet.values()
        for msg in messages:
            if is_nearby(
                fetch_info['latitude'],
                fetch_info['longitude'],
                msg.latitude,
                msg.longitude,
                fetch_info['distance']
            ):
                response['messages'] += Message.objects.filter(id=msg.id).values()

        response['status'] = "success"
    else:
        response['status'] = "fail"
        response['description'] = "invalid username or password"

    return HttpResponse(json.dumps(response, cls=ComplexEncoder))

def publish(request):
    publish_info = json.loads(request.POST['json'].encode('utf8'))
    username = publish_info['username']
    passkey  = md5.new(publish_info['password']).hexdigest()

    response = {
        'status':'',
        'description':''
    }
    if User.objects.filter(username__exact=username,passkey__exact=passkey).exists():
        try:
            message = Message(
                user = User.objects.get(username=username),
                category = Category.objects.get(description="default"),
                content = publish_info['content'],
                time = timezone.now(),
                latitude = publish_info['latitude'],
                longitude = publish_info['longitude']
            )
            message.save()
        except ():
            response['status'] = "fail"
            response['description'] = "database error"
        else:
            response['status'] = "success"
    else:
        response['status'] = "fail"
        response['description'] = "invalid username or password"

    return HttpResponse(json.dumps(response))

def deletemsg(request):
    task_info = json.loads(request.POST['json'].encode('utf8'))
    username  = task_info['username']
    passkey   = md5.new(task_info['password']).hexdigest()

    response = {
        'status': '',
        'description': ''
    }
    if User.objects.filter(username__exact=username,passkey__exact=passkey).exists():
        user = User.objects.get(username__exact=username)
        try:
            Message.objects.get(id=task_info['message id'], user=user).delete()
        except Message.DoesNotExist:
            response['status'] = 'fail'
            response['description'] = 'message not exists'
        else:
            response['status'] = 'success'
    else:
        response['status'] = "fail"
        response['description'] = "invalid username or password"

    return HttpResponse(json.dumps(response))
